package com.lemzdo.community.service.impl;

import com.lemzdo.community.dto.NoticeDTO;
import com.lemzdo.community.enums.NoticeStatusEnum;
import com.lemzdo.community.enums.NoticeTypeEnum;
import com.lemzdo.community.exception.CustomizeException;
import com.lemzdo.community.exception.ErrCodeEnum;
import com.lemzdo.community.mapper.NoticeMapper;
import com.lemzdo.community.model.Notice;
import com.lemzdo.community.model.NoticeExample;
import com.lemzdo.community.model.Post;
import com.lemzdo.community.model.User;
import com.lemzdo.community.service.CommentService;
import com.lemzdo.community.service.NoticeService;
import com.lemzdo.community.service.PostService;
import com.lemzdo.community.service.UserService;
import okhttp3.internal.http2.ErrorCode;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class NoticeServiceImpl implements NoticeService {

    @Autowired
    private NoticeMapper noticeMapper;
    @Autowired
    private UserService userService;
    @Autowired
    private PostService postService;
    @Autowired
    private CommentService commentService;


    /**
     * 根据所需要的参数自定义发起通知方法 插入通知到数据库
     *
     * @param senderId        发起通知人的id
     * @param receiverId      接受通知人的id
     * @param postOrCommentId 帖子或者评论的id
     * @param noticeTypeEnum  通知的类型
     *                        刚发起通知都是未读的 所以直接设置成未读 不需要传参
     */
    @Override
    public void createNotice(Integer senderId, Integer receiverId, Integer postOrCommentId,
                             NoticeTypeEnum noticeTypeEnum) {

        //判断 自己给自己回复不需要通知 为了做验证，目前一个人不需要设置 todo...
        /*if(senderId.equals(receiverId)){
            //自己回复自己 无需通知 直接return
            return;
        }*/


        Notice notice = new Notice();
        //设置发起通知人的id
        notice.setSenderId(senderId);
        //设置接受通知人的id
        notice.setReceiverId(receiverId);
        //设置帖子或者评论的id
        notice.setPostOrCommentId(postOrCommentId);
        //设置通知的类型码（点赞，评论）
        notice.setNoticeTypeCode(noticeTypeEnum.getType());
        //设置通知的类型信息
        notice.setNoticeTypeMsg(noticeTypeEnum.getMessage());
        //设置通知的创建时间
        notice.setGmtCreate(System.currentTimeMillis());
        //设置通知的状态（已读，未读）
        notice.setStatus(NoticeStatusEnum.UNREAD.getStatus());

        //将通知插入到数据库
        noticeMapper.insertSelective(notice);

    }


    /**
     * 通过被通知人的id查询我的所有通知
     *
     * @param receiverId userId 即收到通知人的id
     * @return 通知的数据传输模型
     */
    @Override
    public List<NoticeDTO> getAllByReceiverId(Integer receiverId) {
        List<NoticeDTO> noticeDTOList = new ArrayList<>();

        //根据receiverId查询出所有的通知
        NoticeExample example = new NoticeExample();
        example.createCriteria().andReceiverIdEqualTo(receiverId);
        example.setOrderByClause("gmt_create desc");
        List<Notice> notices = noticeMapper.selectByExample(example);

        //遍历所有通知，将所需要的通知的信息以及外加的其他信息存入dto，再存入list
        for (Notice notice : notices) {

            //notice转化为dto
            NoticeDTO noticeDTO = transformToDTO(notice);
            //加入list
            noticeDTOList.add(noticeDTO);
        }

        return noticeDTOList;
    }

    /**
     * 根据收到通知人的id查询通知的数量
     *
     * @param receiverId 收到通知人的id
     * @return 数量
     */
    @Override
    public Integer countByReceiverId(Integer receiverId) {
        NoticeExample example = new NoticeExample();
        example.createCriteria().andReceiverIdEqualTo(receiverId);
        long countLong = noticeMapper.countByExample(example);
        return Math.toIntExact(countLong);
    }


    /**
     * 根据id查出通知
     *
     * @param id 通知的id
     * @return 通知的DTO
     */
    @Override
    public NoticeDTO readNotice(Integer id, User user) {

        Notice notice = noticeMapper.selectByPrimaryKey(id);

        if (notice == null) {
            //通知为空
            throw new CustomizeException(ErrCodeEnum.NOTIFICATION_NOT_FOUND);
        }
        if (!Objects.equals(notice.getReceiverId(), user.getId())) {
            //通知的接受者并不是用户 避免非法用户读取他人消息
            throw new CustomizeException(ErrCodeEnum.READ_NOTIFICATION_FAIL);
        }

        //设置状态为已读
        notice.setStatus(NoticeStatusEnum.READ.getStatus());
        //更新数据到数据库
        noticeMapper.updateByPrimaryKeySelective(notice);

        //notice转化为dto并返回
        return transformToDTO(notice);
    }

    /**
     * 根据notice对象将其转化为dto对象 给上面方法服务
     *
     * @param notice notice对象
     * @return NoticeDTO
     */
    @Override
    public NoticeDTO transformToDTO(Notice notice) {

        NoticeDTO noticeDTO = new NoticeDTO();

        //赋值通知中信息到dto中 时间，状态，id, 类型信息
        BeanUtils.copyProperties(notice, noticeDTO);

        //设置发送信息人的姓名
        noticeDTO.setSenderName(userService.selectByPrimaryKey(notice.getSenderId()).getName());

        //设置帖子标题和帖子id
        if (notice.getNoticeTypeCode() == 1 || notice.getNoticeTypeCode() == 3) {
            //代表通知是作用在帖子上
            //设置帖子标题和id
            noticeDTO.setPostTitle(postService.selectByPrimaryKey(notice.getPostOrCommentId()).getTitle());
            noticeDTO.setPostId(notice.getPostOrCommentId());

        } else {
            //代表通知作用在评论上
            //通过评论的id找到帖子信息 然后赋值帖子id和标题
            Post post = commentService.getPostByCommentId(notice.getPostOrCommentId());
            noticeDTO.setPostTitle(post.getTitle());
            noticeDTO.setPostId(post.getId());
        }

        return noticeDTO;
    }

    /**
     * 通过用户id 获取未读通知
     *
     * @param receiverId 用户id 即 收通知人的id
     * @return 未读通知数
     */
    @Override
    public Integer getUnReadCount(Integer receiverId) {

        NoticeExample example = new NoticeExample();

        //receiverId相等 并且status是未读
        example.createCriteria().andReceiverIdEqualTo(receiverId)
                .andStatusEqualTo(NoticeStatusEnum.UNREAD.getStatus());

        return Math.toIntExact(noticeMapper.countByExample(example));
    }


}
